import pytest
import requests
from unittest.mock import patch, MagicMock


# 假设这是封装的API请求函数（需要根据实际情况实现）
def describe_instance_families(region: str):
    url = "https://cvm.tencentcloudapi.com/"
    params = {
        "Action": "DescribeInstanceFamilyConfigs",
        "Version": "2017-03-12",
        "Region": region,
        # 其他公共参数需要按腾讯云要求添加（如Signature等）
    }
    response = requests.get(url, params=params)
    response.raise_for_status()  # 这里会触发HTTPError
    return response.json()


# 测试用例
class TestDescribeInstanceFamilies:
    @pytest.fixture(autouse=True)
    def setup(self):
        self.expected_families = {
            "标准型S1", "网络优化型N1", "高IO型I1", "内存型M1",
            "标准型S2", "标准型SN2", "高IO型I2", "内存型M2",
            "计算型C2", "计算型CN2", "标准型S3", "计算型C3",
            "FPGA型FX2", "GPU计算型GN2", "GPU渲染型GA2",
            "GPU计算型GN8", "独享型", "共享核", "特殊机型", "其他"
        }

    @patch("requests.get")
    def test_normal_case(self, mock_get):
        """测试正常查询"""
        # 构造模拟响应
        mock_response = MagicMock(spec=requests.Response)
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "Response": {
                "InstanceFamilyConfigSet": [
                    {"InstanceFamilyName": name, "InstanceFamily": name[0:2]}
                    for name in self.expected_families
                ],
                "RequestId": "mock-request-id"
            }
        }
        mock_response.raise_for_status.return_value = None  # 正常情况无需抛出异常
        mock_get.return_value = mock_response

        # 执行测试
        result = describe_instance_families(region="ap-guangzhou")

        # 验证结果
        assert result["Response"]["InstanceFamilyConfigSet"]
        assert len(result["Response"]["InstanceFamilyConfigSet"]) == len(self.expected_families)
        for family in self.expected_families:
            assert any(item["InstanceFamilyName"] == family for item in result["Response"]["InstanceFamilyConfigSet"])

    @patch("requests.get")
    def test_missing_region(self, mock_get):
        """测试缺少Region参数"""
        mock_response = MagicMock(spec=requests.Response)
        mock_response.status_code = 400
        mock_response.json.return_value = {
            "Response": {
                "Error": {
                    "Code": "InvalidParameterValue",
                    "Message": "Region parameter is required"
                }
            }
        }
        # 直接调用raise_for_status()触发异常
        mock_response.raise_for_status.side_effect = requests.HTTPError(
            response=mock_response
        )
        mock_get.return_value = mock_response

        # 执行测试
        with pytest.raises(requests.HTTPError) as exc_info:
            describe_instance_families(region="")

        # 从响应对象中提取错误信息
        error_response = exc_info.value.response.json()
        assert error_response["Response"]["Error"]["Code"] == "InvalidParameterValue"

    @patch("requests.get")
    def test_invalid_region(self, mock_get):
        """测试无效Region"""
        mock_response = MagicMock(spec=requests.Response)
        mock_response.status_code = 400
        mock_response.json.return_value = {
            "Response": {
                "Error": {
                    "Code": "InvalidRegion.NotFound",
                    "Message": "The specified region is not found"
                }
            }
        }
        mock_response.raise_for_status.side_effect = requests.HTTPError(
            response=mock_response
        )
        mock_get.return_value = mock_response

        # 执行测试
        with pytest.raises(requests.HTTPError) as exc_info:
            describe_instance_families(region="invalid-region")

        error_response = exc_info.value.response.json()
        assert error_response["Response"]["Error"]["Code"] == "InvalidRegion.NotFound"

    @patch("requests.get")
    def test_api_failure(self, mock_get):
        """测试API内部错误"""
        mock_response = MagicMock(spec=requests.Response)
        mock_response.status_code = 500
        mock_response.json.return_value = {
            "Response": {
                "Error": {
                    "Code": "InternalServerError",
                    "Message": "Internal server error occurred"
                }
            }
        }
        mock_response.raise_for_status.side_effect = requests.HTTPError(
            response=mock_response
        )
        mock_get.return_value = mock_response

        # 执行测试
        with pytest.raises(requests.HTTPError) as exc_info:
            describe_instance_families(region="ap-guangzhou")

        error_response = exc_info.value.response.json()
        assert error_response["Response"]["Error"]["Code"] == "InternalServerError"

    @patch("requests.get")
    def test_network_error(self, mock_get):
        """测试网络错误"""
        mock_get.side_effect = requests.ConnectionError("Network connection failed")

        # 执行测试
        with pytest.raises(requests.ConnectionError):
            describe_instance_families(region="ap-guangzhou")


# 运行测试
if __name__ == "__main__":
    pytest.main([__file__, "-s"])